home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / jf90.lha / ModularIV-41.ascii < prev    next >
Encoding:
Text File  |  1990-03-26  |  54.0 KB  |  2,021 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either express or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8. Modular Event Processing
  9.  
  10. by David N. Junod
  11.  
  12. On the Amiga, input to an application can come from many different sources 
  13. such as Intuition (through menu selections, gadget selections or the 
  14. keyboard), Exec (through an inter-process communications method, such as 
  15. ARexx) or even DOS (through a console-based command shell).  With the 
  16. increase in popularity of inter-process communication, it  is more important 
  17. than ever to use a modular programming methodology.  A modular design 
  18. incorporates reusable program components which are independent of the 
  19. various user interfaces.
  20.  
  21. The C source code that follows this article is an example of a modularly 
  22. programmed application.  It illustrates how to set up functions in a way 
  23. that will keep the menu, gadget, and keyboard processing overhead to a 
  24. minimum.  This is achieved by setting up the program's functions with a 
  25. consistent set of parameters, so that very different input sources can easily 
  26. interface to the same functions.  In this way the same code which handles a 
  27. menu selection from Intuition can also be used to handle the command 
  28. equivalent from an ARexx macro or a hot-key equivalent from the keyboard. 
  29.  
  30. The heart of this programming example is its function table.  The function 
  31. table is simply an array of pointers to all the modular functions within the 
  32. program.  Each component of the user interface is assigned a number that 
  33. references an entry in the function table.  Whenever a particular component 
  34. of the user interface is triggered, the corresponding entry from the function 
  35. table is executed.  The example program, named modengine1.c, covers processing 
  36. Intuition messages, ARexx macros, command shell input from a DOS console and 
  37. hot-key equivalents. 
  38.  
  39. This engine can be used as the basic foundation for almost any application.  
  40. The main processing loop would remain constant.  You would add your own 
  41. routines  by including them in the function table and linking them in at 
  42. compile time.  Modengine1.c includes a Project Menu with all the standard 
  43. items: New, Open, Save, Save As, About and Quit. 
  44.  
  45. The program  also includes a small window showing four different Intuition 
  46. gadget types: downpress, hold, release, and double-click.  A fifth gadget 
  47. will send an ARexx macro.  There is also a menu named User which shows how 
  48. you can provide a command shell using a DOS console window.
  49.  
  50. The components of the program are shown in the figure below:
  51.  
  52.  
  53. Intuition Input            ARexx Input        Command Shell  Input
  54. ---------------           ---------------     --------------------
  55. Handles menus,             Handles ARexx       Handles commands
  56. gadgets, and keyboard.     scripts.            from a DOS console.
  57. (mod_idcmp.c)             (mod_arexx.c)          (mod_dos.c)
  58.  
  59.  
  60.  
  61.                        Input Event Processing
  62.                       ------------------------
  63.                        Converts events into 
  64.                        function calls via lookup
  65.                        in a function table.
  66.                          (modengine1.c)
  67.  
  68.  
  69.                        Application Functions
  70.                      --------------------------
  71.                       A set of functions with
  72.                       consistent parameters that
  73.                       that perform the actions 
  74.                       requested by the input event.
  75.                            (mod_funcs.c)
  76.  
  77.  
  78. Many of the functions such as those found in the Project and Edit menu strips,
  79. as well as the processing for the ESC, DEL and HELP keys, can remain the same 
  80. from application to application.  Using this approach will promote consistency
  81. between applications, and it cuts your coding time to a minimum by eliminating 
  82. the need to re-code the common elements found in most applications.
  83.  
  84. Another benefit of this approach is that it is easier to make your application
  85. user-configurable.  You would only have to provide a means of editing the 
  86. text and the function numbers of each of the menu items, gadgets and keys.  
  87. Internationalization would become a very simple matter.  As part of the 
  88. implementation, modengine1.c illustrates some other techniques which are 
  89. useful to Amiga programmers:
  90.  
  91. o  How to add an ARexx port to an application and handle the IPC events.
  92. o  How to add a command shell to your application using a DOS console.
  93. o  How to handle the project menu (and a project).  
  94. o  How to prevent overloading of mouse movements.  
  95. o  How to convert and handle raw keys.  
  96. o  How to determine if a gadget has been double-clicked.
  97. o  How to avoid using global variables (using the UserData field of 
  98.        Intuition structures).
  99.  
  100. The lmkfile (Lattice make file) is shown below.  To compile modengine1.c, 
  101. use the lmk command under Lattice 5.04.  The listing is composed of six 
  102. source files and two header files.  These should be stored with the lmkfile 
  103. in one directory.
  104.  
  105. # lmk file for modengine1
  106. # Copyright (C) 1989, 1990 Commodore-Amiga, Inc.
  107. # written by David N. Junod
  108.  
  109. COFILES  = modengine1.o mod_misc.o mod_arexx.o mod_dos.o mod_idcmp.o mod_funcs.o
  110. CFLAGS  = -cfist -ms -v -d2
  111.  
  112. LFILES  = $(COFILES)
  113. LDFLAGS = SMALLCODE SMALLDATA
  114. LLIBS  = lib lib:lc.lib lib:amiga.lib lib:debug.lib
  115.  
  116. .c.o:
  117.   lc $(CFLAGS) $*
  118.  
  119. all:  modengine1
  120.  
  121. modengine1: modengine1.ld
  122.   BLink modengine1.ld to modengine1 NODEBUG
  123.  
  124. modengine1.ld: $(COFILES) LMKfile
  125.   blink <with <
  126. FROM lib:c.o lib:rexxglue.o $(LFILES)
  127. $(LDFLAGS)
  128. $(LLIBS)
  129. to modengine1.ld
  130. <
  131.  
  132.  
  133.  
  134. /* mod.h
  135.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  136.  * written by David N. Junod
  137.  *
  138.  * header file for modengine1
  139.  * event processing engine structures & definitions
  140.  *
  141.  */
  142.  
  143. #include <intuition/intuition.h>
  144. #include <rexx/storage.h>    /* off of ARexx disk */
  145. #include <rexx/rxslib.h>    /* off of ARexx disk */
  146. #include <exec/ports.h>
  147. #include <exec/memory.h>
  148. #include <libraries/dos.h>
  149. #include <libraries/dosextens.h>
  150. #include <devices/inputevent.h>
  151. #include <proto/all.h>
  152. #include <stdio.h>
  153. #include <stdlib.h>
  154. #include <string.h>
  155.  
  156.  
  157. /* mod_funcs.c: application functions */
  158. VOID NewFunc    (struct AppInfo *, struct Message *, UBYTE *args );
  159. VOID OpenFunc   (struct AppInfo *, struct Message *, UBYTE *args );
  160. VOID SaveFunc   (struct AppInfo *, struct Message *, UBYTE *args );
  161. VOID SaveAsFunc (struct AppInfo *, struct Message *, UBYTE *args );
  162. VOID AboutFunc  (struct AppInfo *, struct Message *, UBYTE *args );
  163. VOID QuitFunc   (struct AppInfo *, struct Message *, UBYTE *args );
  164. VOID ChooseFunc (struct AppInfo *, struct Message *, UBYTE *args );
  165. VOID DefineFunc (struct AppInfo *, struct Message *, UBYTE *args );
  166. VOID UndoFunc   (struct AppInfo *, struct Message *, UBYTE *args );
  167. VOID HelpFunc   (struct AppInfo *, struct Message *, UBYTE *args );
  168. VOID ArrowFunc  (struct AppInfo *, struct Message *, UBYTE *args );
  169. VOID ShellFunc  (struct AppInfo *, struct Message *, UBYTE *args );
  170. VOID WindowFunc (struct AppInfo *, struct Message *, UBYTE *args );
  171.  
  172. #define APPNAME "Our Application"
  173.  
  174. /* modengine1.c: initialization & dispatching routines */
  175. VOID main ( void );
  176. struct AppInfo *OpenAll ( void );
  177. VOID CloseAll (struct AppInfo *, int value , UBYTE *fmsg );
  178. BOOL HandlerFunc (struct AppInfo *, UBYTE * name, WORD function);
  179. struct MsgHandler * HandlerData (struct AppInfo *, UBYTE * name);
  180. BOOL AddMsgHandler (struct AppInfo *, struct MsgHandler *, BOOL);
  181. BOOL PerfFunc (struct AppInfo *, struct Message *, UBYTE *);
  182.  
  183. /* mod_misc.c: misc. functions */
  184. BOOL NotifyUser (struct Window *, UBYTE *);
  185. BOOL CheckForChanges (struct AppInfo * ai);
  186.  
  187.  
  188.  
  189.  
  190. /*
  191.  * message handler node 
  192. */
  193. struct MsgHandler
  194. {
  195.     struct Node mh_Node;
  196.     ULONG mh_SigBits;        /* signal bits to watch for */
  197.     WORD mh_Status;        /* current status */
  198.  
  199.     /* interface functions */
  200.     BOOL (*mh_Func[4])(struct AppInfo *, struct MsgHandler *);
  201.     VOID *mh_Data;        /* handler context data */
  202. };
  203.  
  204. #define    MH_OPEN        0    /* make a handler active */
  205. #define    MH_HANDLE    1    /* handle messages */
  206. #define    MH_CLOSE        2    /* make a handler inactive */
  207. #define    MH_SHUTDOWN    3    /* free resources and delete handler */
  208.  
  209. /* component for our function table */
  210. struct Funcs
  211. {
  212.     UBYTE *name;
  213.     VOID (*func)(struct AppInfo *, struct Message *, UBYTE *);
  214. };
  215.  
  216. #define    NO_FUNCTION    NULL        /* no internal function defined for event */
  217.  
  218. /*--- AREXX RELATED ITEMS -------------------------------------------------*/
  219. /* mod_arexx.c: AREXX message handling routines */
  220. struct MsgHandler *setup_arexx (struct AppInfo *, UBYTE *, UBYTE *, BOOL);
  221. BOOL open_arexx (struct AppInfo *, struct MsgHandler * );
  222. BOOL handle_arexx (struct AppInfo *, struct MsgHandler * );
  223. BOOL close_arexx (struct AppInfo *, struct MsgHandler * );
  224. BOOL shutdown_arexx (struct AppInfo *, struct MsgHandler * );
  225.  
  226. #define AR_EXECUTE 0    /* ARexx status definitions */
  227. #define    AR_SUSPEND 1
  228.  
  229. /*--- DOS SHELL RELATED ITEMS ---------------------------------------------*/
  230. /* mod_dos.c: DOS message handling routines */
  231. struct MsgHandler *setup_dos (struct AppInfo *,UBYTE *,UBYTE *,UBYTE *, BOOL);
  232. BOOL open_dos (struct AppInfo *, struct MsgHandler *mh);
  233. BOOL handle_dos (struct AppInfo *, struct MsgHandler *mh);
  234. BOOL close_dos (struct AppInfo *, struct MsgHandler *mh);
  235. BOOL shutdown_dos (struct AppInfo *, struct MsgHandler *mh);
  236.  
  237. /* DOS shell status definitions */
  238. #define AS_CLOSED 0
  239. #define AS_CLOSING 1
  240. #define AS_GOING 2
  241. #define AS_OPEN 3
  242.  
  243. #define BUFFLEN      100
  244.  
  245. /*--- IDCMP RELATED ITEMS -------------------------------------------------*/
  246. /* mod_idcmp.c: IDCMP message handling routines */
  247. struct MsgHandler * setup_idcmp ( struct AppInfo *,
  248.          struct NewWindow *,struct KeyboardCMD *,struct Menu *,BOOL);
  249. BOOL open_idcmp (struct AppInfo *, struct MsgHandler *);
  250. BOOL handle_idcmp (struct AppInfo *, struct MsgHandler *);
  251. BOOL close_idcmp (struct AppInfo *, struct MsgHandler *);
  252. BOOL shutdown_idcmp (struct AppInfo *, struct MsgHandler *);
  253.  
  254. /*--- MENU RELATED ITEMS ---*/
  255. struct EMenuItem                /* Extended MenuItem structure */
  256. {
  257.     struct MenuItem emi_Item;    /* embedded MenuItem structure */
  258.     UWORD emi_MenuID;            /* ID used for function number to perform */
  259.     VOID *emi_UserData;        /* UserData (like other Intuition structs) */
  260. };
  261.  
  262. /*--- GADGET RELATED ITEMS ---*/
  263. struct EGadget                /* Extended Gadget structure */
  264. {
  265.     struct Gadget eg_Gadget;    /* embedded Gadget structure */
  266.     WORD eg_Funcs[5];            /* Function array */
  267. };
  268. #define    EG_DOWNPRESS    0    /* Extended Gadget function array pointers */
  269. #define    EG_HOLD        1
  270. #define    EG_RELEASE    2
  271. #define    EG_DBLCLICK    3
  272. #define    EG_ABORT        4
  273.  
  274. /*--- KEYBOARD RELATED ITEMS ---*/
  275. #define    MAXKEYS    512            /* some useful defines */
  276. #define    SPECIAL 255
  277. #define    ESC    27        
  278. #define    DELETE    127
  279. #define    HELP    (SPECIAL + '?')
  280. #define    FUNC1    (SPECIAL + '0')
  281. #define    FUNC2    (SPECIAL + '1')
  282. #define    FUNC3    (SPECIAL + '2')
  283. #define    FUNC4    (SPECIAL + '3')
  284. #define    FUNC5    (SPECIAL + '4')
  285. #define    FUNC6    (SPECIAL + '5')
  286. #define    FUNC7    (SPECIAL + '6')
  287. #define    FUNC8    (SPECIAL + '7')
  288. #define    FUNC9    (SPECIAL + '8')
  289. #define    FUNC10    (SPECIAL + '9')
  290. #define    UP    (SPECIAL + 'A')
  291. #define    DOWN    (SPECIAL + 'B')
  292. #define    RIGHT    (SPECIAL + 'C')
  293. #define    LEFT    (SPECIAL + 'D')
  294.  
  295. /* component for our keyboard command array */
  296. struct KeyboardCMD
  297. {
  298.     WORD key;
  299.     WORD funcID;
  300. };
  301.  
  302. /*--- GLOBAL DATA -----------------------------------------------------------*/
  303. /* AppInfo structure that contains our global variables */
  304. struct AppInfo
  305. {
  306.     struct List MsgList;    /* List of message handlers */
  307.     ULONG sigbits;        /* Sum of all signals */
  308.     struct Funcs *FuncTable;    /* Pointer to the function table */
  309.     BOOL Done;            /* Done with main loop? */
  310.     WORD numcmds;        /* Outstanding commands */
  311.     LONG pri_ret;        /* Primary error return value */
  312.     LONG sec_ret;        /* Secondary error return value */
  313.     UBYTE *textrtn;        /* Text return string */
  314.  
  315.     /* Project information */
  316.     UBYTE ProjPath[255];    /* Path of project */
  317.     UBYTE ProjName[31];        /* Name of project */
  318.     BOOL Changed;        /* Changes made to project? */
  319. };
  320.  
  321.  
  322.  
  323. /* modengine1.h
  324.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  325.  * written by David N. Junod
  326.  *
  327.  * header file for modengine1.c
  328.  * application-specific arrays & definitions
  329.  */
  330.  
  331. /* Modular Function ID's */
  332. enum
  333. {
  334.     NewID = 1,
  335.     OpenID,
  336.     SaveID,
  337.     SaveAsID,
  338.     AboutID,
  339.     QuitID,
  340.     ChooseID,
  341.     DefineID,
  342.     UndoID,
  343.     HelpID,
  344.     ArrowID,
  345.     ShellID,
  346.     Macro1ID,
  347.     WindowID,
  348.     LAST_ID
  349. };
  350.  
  351. /* Modular Function Table */
  352. struct Funcs FTable[] =
  353. {
  354.     {NULL,     NO_FUNCTION},    /* padding, for alignment */
  355.     {"NEW",    NewFunc},
  356.     {"OPEN",   OpenFunc},
  357.     {"SAVE",   SaveFunc},
  358.     {"SAVEAS", SaveAsFunc},
  359.     {"ABOUT",  AboutFunc},
  360.     {"QUIT",   QuitFunc},
  361.     {"CHOOSE", ChooseFunc},
  362.     {"DEFINE", DefineFunc},
  363.     {"UNDO",   UndoFunc},
  364.     {"HELP",   HelpFunc},
  365.     {"ARROW",  ArrowFunc},
  366.     {"SHELL",  ShellFunc},
  367.     {"MACRO1", NO_FUNCTION},    /* calls an ARexx macro */
  368.     {"WINDOW", WindowFunc},
  369.     {NULL,     NO_FUNCTION}    /* end of array */
  370. };
  371.  
  372. /* Text attribute to use for our text */
  373. struct TextAttr Topaz80 = {"topaz.font", 8, NULL, NULL};
  374.  
  375. /* The menu structures for our 'application' */
  376. struct IntuiText UserT[] =
  377. {
  378.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "Command Shell",   NULL},
  379.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "ARexx Macro 1", NULL}
  380. };
  381.  
  382.  
  383.  
  384. /* MenuItem structure using our extended structure */
  385. struct EMenuItem UserI[] =
  386. {
  387.     {NULL,               0, 0, 168, 9,
  388.      ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  389.      0, (APTR) & UserT[0], NULL, 'E', NULL, MENUNULL, ShellID, NULL},
  390.  
  391.     {&UserI[0].emi_Item, 0, 9, 168, 9,
  392.      ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  393.      0, (APTR) & UserT[1], NULL, '1', NULL, MENUNULL, Macro1ID, NULL}
  394. };
  395.  
  396.  
  397. /* Text for our Menu Items */
  398. struct IntuiText ProjT[] =
  399. {
  400.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "New", NULL},
  401.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "Open...", NULL},
  402.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "Save", NULL},
  403.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "Save As...", NULL},
  404.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "About...", NULL},
  405.     {2, 1, COMPLEMENT, 2, 1, &Topaz80, "Quit", NULL}
  406. };
  407.  
  408. /* Extended Menu Item structures for our Application */
  409. struct EMenuItem ProjI[] =
  410. {
  411.     {NULL,               0, 51, 148, 9,
  412.      ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  413.      0, (APTR) & ProjT[5], NULL, 'Q', NULL, MENUNULL, QuitID, NULL},
  414.     {&ProjI[0].emi_Item, 0, 40, 148, 9,
  415.      ITEMTEXT | ITEMENABLED | HIGHCOMP,
  416.      0, (APTR) & ProjT[4], NULL, NULL, NULL, MENUNULL, AboutID, NULL},
  417.     {&ProjI[1].emi_Item, 0, 29, 148, 9,
  418.      ITEMTEXT | ITEMENABLED | HIGHCOMP,
  419.      0, (APTR) & ProjT[3], NULL, NULL, NULL, MENUNULL, SaveAsID, NULL},
  420.     {&ProjI[2].emi_Item, 0, 20, 148, 9,
  421.      ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  422.      0, (APTR) & ProjT[2], NULL, 'S', NULL, MENUNULL, SaveID, NULL},
  423.     {&ProjI[3].emi_Item, 0, 9, 148, 9,
  424.      ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP,
  425.      0, (APTR) & ProjT[1], NULL, 'O', NULL, MENUNULL, OpenID, NULL},
  426.     {&ProjI[4].emi_Item, 0, 0, 148, 9,
  427.      ITEMTEXT | ITEMENABLED | HIGHCOMP,
  428.      0, (APTR) & ProjT[0], NULL, NULL, NULL, MENUNULL, NewID, NULL}
  429. };
  430.  
  431.  
  432. /* Menu structure */
  433. struct Menu Menu2 =
  434. {NULL,  70, 0, 87, 0, MENUENABLED, "User",    &UserI[1].emi_Item};
  435. struct Menu Menu1 =
  436. {&Menu2, 0, 0, 63, 0, MENUENABLED, "Project", &ProjI[5].emi_Item};
  437.  
  438.  
  439. /* Text for our Gadgets */
  440. struct IntuiText GadgT[] =
  441. {
  442.     {2, 1, JAM2, 2, 1, &Topaz80, "   DownPress  ", NULL},
  443.     {2, 1, JAM2, 2, 1, &Topaz80, "     Hold     ", NULL},
  444.     {2, 1, JAM2, 2, 1, &Topaz80, "    Release   ", NULL},
  445.     {2, 1, JAM2, 2, 1, &Topaz80, " Double-Click ", NULL},
  446.     {2, 1, JAM2, 2, 1, &Topaz80, " ARexx Macro  ", NULL}
  447. };
  448.  
  449.  
  450.  
  451.  
  452.  
  453. /* extended Gadgets structures for our application */
  454. struct EGadget Gadg[] =
  455. {
  456.     {NULL,               67, 15, 115, 10, NULL, GADGIMMEDIATE | RELVERIFY,
  457.      BOOLGADGET, NULL, NULL, &GadgT[0], NULL, NULL, NULL, NULL,
  458.      ChooseID, NO_FUNCTION, NO_FUNCTION, NO_FUNCTION, NO_FUNCTION},
  459.  
  460.     {&Gadg[0].eg_Gadget, 67, 29, 115, 10, NULL, GADGIMMEDIATE | RELVERIFY,
  461.      BOOLGADGET, NULL, NULL, &GadgT[1], NULL, NULL, NULL, NULL,
  462.      ArrowID, ArrowID, NO_FUNCTION, NO_FUNCTION, NO_FUNCTION},
  463.  
  464.     {&Gadg[1].eg_Gadget, 67, 43, 115, 10, NULL, GADGIMMEDIATE | RELVERIFY,
  465.      BOOLGADGET, NULL, NULL, &GadgT[2], NULL, NULL, NULL, NULL,
  466.      NO_FUNCTION, NO_FUNCTION, UndoID, NO_FUNCTION, NO_FUNCTION},
  467.  
  468.     {&Gadg[2].eg_Gadget, 67, 58, 115, 10, NULL, GADGIMMEDIATE | RELVERIFY,
  469.      BOOLGADGET, NULL, NULL, &GadgT[3], NULL, NULL, NULL, NULL,
  470.      ChooseID, NO_FUNCTION, NO_FUNCTION, DefineID, NO_FUNCTION},
  471.  
  472.     {&Gadg[3].eg_Gadget, 67, 73, 115, 10, NULL, GADGIMMEDIATE | RELVERIFY,
  473.      BOOLGADGET, NULL, NULL, &GadgT[4], NULL, NULL, NULL, NULL,
  474.      NO_FUNCTION, NO_FUNCTION, Macro1ID, NO_FUNCTION, NO_FUNCTION}
  475. };
  476.  
  477. /*
  478.  * Set up the keyboard function map. If you are a word processor,
  479.  * then you could set up all the text-related keys to the same
  480.  * function.
  481.  */
  482. struct KeyboardCMD KeyArray[] =
  483. {
  484.     {'u',  UndoID},        /* u will call the Undo function */
  485.     {ESC,  QuitID},        /* ESC to quit */
  486.     {HELP, HelpID},        /* HELP to call the help function */
  487.     {UP,   ArrowID},        /* Up arrow */
  488.     {DOWN, ArrowID},        /* Down arrow */
  489.     {FUNC1,Macro1ID},        /* Call an ARexx macro */
  490.     {NULL, NO_FUNCTION}        /* end of array */
  491. };
  492.  
  493. /* NewWindow structure */
  494. struct NewWindow NewWindow =
  495. {
  496.     0, 10, 250, 90, 2, 1,
  497.     NULL,
  498.     WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | ACTIVATE | NOCAREREFRESH
  499.     | REPORTMOUSE,
  500.     &Gadg[4].eg_Gadget, NULL, APPNAME, NULL, NULL,
  501.     60, 30, 1024, 1024, WBENCHSCREEN,
  502. };
  503.  
  504.  
  505.  
  506.  
  507. /* ModEngine1.c
  508.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  509.  * written by David N. Junod
  510.  *
  511.  * Modular event processing shell for Intuition
  512.  */
  513. #include "mod.h"
  514. #include "ModEngine1.h"
  515.  
  516. struct IntuitionBase *IntuitionBase = NULL;    /* Required for Intuition processing */
  517.  
  518. /* Main processing loop */
  519. VOID main ()
  520. {
  521.     struct AppInfo *ai = NULL;
  522.     struct List *list = NULL;
  523.     struct Node *node = NULL;
  524.     struct MsgHandler *mh = NULL;
  525.     ULONG sig_rcvd;
  526.  
  527.     /* Obtain the needed resources */
  528.     ai = OpenAll ();
  529.     list = &(ai->MsgList);
  530.  
  531.     /* Process messages until user signals that they are done and no messages outstanding */
  532.     while (!ai->Done || ai->numcmds)
  533.     {
  534.     /* wait for a message to come in */
  535.     sig_rcvd = Wait (ai->sigbits);
  536.  
  537.     /* process signals */
  538.     if (list->lh_TailPred != (struct Node *) list)
  539.         for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
  540.         {
  541.         mh = (struct MsgHandler *) node;
  542.         if (mh->mh_SigBits & sig_rcvd)
  543.             (*mh->mh_Func[MH_HANDLE]) (ai, mh);
  544.         }
  545.     }
  546.  
  547.     /* Free up all the resources cleanly */
  548.     CloseAll (ai, RETURN_OK, NULL);
  549. }
  550.  
  551. /*--- Obtain the needed resources ---*/
  552. struct AppInfo *OpenAll ()
  553. {
  554.     struct AppInfo *ai = NULL;
  555.     /* open required libraries here */
  556.     if (!(IntuitionBase = (struct IntuitionBase *)
  557.       OpenLibrary ("intuition.library", 33L)))
  558.     {
  559.     CloseAll (ai, RETURN_FAIL, "Could not open intuition.library");
  560.     }
  561.  
  562.     /* Allocate memory for all our variables */
  563.     if (!(ai = (struct AppInfo *)
  564.       AllocMem (sizeof (struct AppInfo), MEMF_CLEAR)))
  565.     CloseAll (ai, RETURN_FAIL, "Not enough memory");
  566.  
  567.  
  568.  
  569.     /* Initialize the message handler list */
  570.     NewList (&(ai->MsgList));
  571.  
  572.     /* set up the function table pointer */
  573.     ai->FuncTable = &FTable[0];
  574.  
  575.     /* set up ARexx message handler */
  576.     if (!(AddMsgHandler (ai,
  577.          setup_arexx (ai, "OURAPP", "mod", TRUE),
  578.          FALSE))) /* handler not required */
  579.     CloseAll (ai, RETURN_FAIL, "Could not allocate ARexx resources");
  580.  
  581.     /* set up DOS command shell message handler */
  582.     if (!(AddMsgHandler (ai,
  583.          setup_dos (ai, "CON:0/150/600/50/Command Window",
  584.                 "Cmd>", "Waiting for message(s)\n", FALSE),
  585.          FALSE))) /* handler not required */
  586.     CloseAll (ai, RETURN_FAIL, "Could not allocate DOS resources");
  587.  
  588.     /* set up IDCMP message handler */
  589.     if (!(AddMsgHandler (ai,
  590.          setup_idcmp (ai, &NewWindow, KeyArray, &Menu1, TRUE),
  591.          TRUE))) /* handler required */
  592.     CloseAll (ai, RETURN_FAIL, "Could not allocate IDCMP resources");
  593.  
  594.     return (ai);
  595. }
  596.  
  597.  
  598. /*--- Free up all the resources that we obtained ---*/
  599. VOID CloseAll (struct AppInfo * ai, int value, UBYTE * fmsg)
  600. {
  601.     struct List *list = &(ai->MsgList);
  602.     struct Node *node = NULL, *nxtnode = NULL;
  603.     struct MsgHandler *mh = NULL;
  604.  
  605.     /* display error message, if there is one */
  606.     if (fmsg)
  607.     NotifyUser (NULL, fmsg);
  608.  
  609.     /* shutdown all the handlers */
  610.     if (list->lh_TailPred != (struct Node *) list)
  611.     {
  612.     node = list->lh_Head;
  613.     while (nxtnode = node->ln_Succ)
  614.       {
  615.         mh = (struct MsgHandler *) node;
  616.         (*mh->mh_Func[MH_SHUTDOWN]) (ai, mh);
  617.         node = nxtnode;
  618.       }
  619.     }
  620.  
  621.     /* free our variable space */
  622.     if (ai)
  623.     FreeMem (ai, sizeof (struct AppInfo));
  624.  
  625.     /* close down libraries now */
  626.     if (IntuitionBase)
  627.     CloseLibrary ((struct Library *) IntuitionBase);
  628.  
  629.     exit (value);
  630. }
  631.  
  632.  
  633.  
  634. /* add a message handler node to the handler list */
  635. BOOL AddMsgHandler (struct AppInfo * ai, struct MsgHandler * mh,
  636.             BOOL needed)
  637. {
  638.     BOOL retval = FALSE;
  639.  
  640.     if (mh)
  641.     {
  642.     AddTail (&(ai->MsgList), (struct Node *) mh);
  643.     ai->sigbits |= mh->mh_SigBits;
  644.     retval = TRUE;
  645.     }
  646.     return ( (BOOL)((needed) ? retval : TRUE) );
  647. }
  648.  
  649.  
  650. /* handle messages between function handlers */
  651. BOOL HandlerFunc (struct AppInfo * ai, UBYTE * name, WORD function)
  652. {
  653.     BOOL retval = FALSE;
  654.     struct MsgHandler * mh;
  655.  
  656.     if (mh = (struct MsgHandler *)FindName (&(ai->MsgList), name))
  657.     {
  658.     if (mh->mh_Func[function])
  659.         retval = (*mh->mh_Func[function])(ai, mh);
  660.     }
  661.     return (retval);
  662. }
  663.  
  664. /* get handler data */
  665. struct MsgHandler * HandlerData (struct AppInfo * ai, UBYTE * name)
  666. {
  667.     return ( (struct MsgHandler *)FindName (&(ai->MsgList), name) );
  668. }
  669.  
  670. /*
  671.  * First checks to see if the command is an internal function and if so,
  672.  * it executes the function.  Otherwise, it passes the command to ARexx.
  673.  */
  674. BOOL PerfFunc (struct AppInfo * ai, struct Message * msg, UBYTE * anchor)
  675. {
  676.     extern BOOL send_rexx_command (UBYTE *, struct AppInfo *,
  677.                    struct MsgHandler *);
  678.     struct MsgHandler * mh = NULL;
  679.     register VOID (*func) (struct AppInfo *, struct Message *, UBYTE *);
  680.     register UBYTE *args = anchor;
  681.     register WORD cntr;
  682.     BOOL retval = FALSE;
  683.     UBYTE arg1[50];
  684.  
  685.     /* get the first word of the command string */
  686.     args = stptok (args, arg1, sizeof (arg1), " ,");
  687.  
  688.     /* increment past first space */
  689.     if (strlen (args) > 0)
  690.     ++args;
  691.  
  692.     /* check the array to see if it is a name that we understand */
  693.     for (cntr = 1, func = NO_FUNCTION;
  694.      (ai->FuncTable[cntr].name != NULL) && (func == NO_FUNCTION);
  695.      cntr++)
  696.     {
  697.     if ((strcmpi (arg1, ai->FuncTable[cntr].name)) == 0)
  698.         func = ai->FuncTable[cntr].func;
  699.     }
  700.  
  701.  
  702.     /* preset the error return to zero */
  703.     ai->pri_ret = 0L;
  704.  
  705.     if (func != NO_FUNCTION)
  706.     {
  707.     /* valid internal function, let's execute it */
  708.  
  709.     /* execute the function */
  710.     (*(func)) (ai, (struct Message *) msg, args);
  711.  
  712.     /* successful command completion */
  713.     retval = TRUE;
  714.     }
  715.     else
  716.     {
  717.     /* see if we are using ARexx */
  718.     if (mh = HandlerData (ai, "AREXX"))
  719.       {
  720.         /* wasn't an internal function, so let's pass it to ARexx */
  721.         if (!send_rexx_command (anchor, ai, mh))
  722.         {
  723.         /* ARexx failed (not present) */
  724.         NotifyUser (NULL, "ARexx not present");
  725.         }
  726.         else
  727.         /* successful command completion */
  728.         retval = TRUE;
  729.       }
  730.     }
  731.  
  732.     return (retval);
  733. }
  734.  
  735.  
  736.  
  737.  
  738. /* mod_arexx.c
  739.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  740.  * written by David N. Junod
  741.  *
  742.  * AREXX message handling routines
  743.  */
  744. #include "mod.h"
  745.  
  746. /* variables required for ARexx */
  747. struct data_arexx
  748. {
  749.     struct MsgPort *rxport;    /* ARexx message port */
  750.     UBYTE *portname;    /* ARexx message port name */
  751.     UBYTE *extens;        /* ARexx macro name extension */
  752.     BOOL astatus;        /* ARexx status */
  753. };
  754.  
  755. /* ARexx message handling routines */
  756. BOOL send_rexx_command (UBYTE *, struct AppInfo *, struct MsgHandler *);
  757. VOID execute_command (struct RexxMsg *,struct AppInfo *,struct MsgHandler *);
  758. VOID reply_rexx_command (struct RexxMsg *,struct AppInfo *,struct MsgHandler *);
  759.  
  760. /* ARexx Functions Prototypes */
  761. struct RexxMsg *CreateRexxMsg (struct MsgPort *, UBYTE *, UBYTE *);
  762. STRPTR CreateArgstring (UBYTE *, int);
  763. VOID DeleteRexxMsg (struct RexxMsg *);
  764. VOID DeleteArgstring (UBYTE *);
  765. BOOL IsRexxMsg (struct Message *);
  766.  
  767. /* Required for ARexx processing */
  768. struct RxsLib *RexxSysBase = NULL;
  769.  
  770. struct MsgHandler *setup_arexx (struct AppInfo * ai, UBYTE * pname,
  771.                 UBYTE * extens, BOOL immed)
  772. {
  773.     UBYTE *portname = "                        ";
  774.     register WORD cntr = 1;
  775.     BOOL exist = TRUE, retval = FALSE;
  776.     struct MsgHandler *mh = NULL;
  777.     struct data_arexx *md = NULL;
  778.  
  779.     if (md = (struct data_arexx *)
  780.     AllocMem (sizeof (struct data_arexx), MEMF_CLEAR))
  781.     {
  782.     md->portname = pname;
  783.     md->extens = extens;
  784.     if (RexxSysBase = 
  785.                 (struct RsxLib *) OpenLibrary ("rexxsyslib.library", 0L))
  786.     {
  787.         Forbid ();        /* forbid multi-tasking while we try to get a port */
  788.  
  789.         /* get an unique port name */
  790.         while (exist)
  791.         {
  792.             /* create a name with our base name and a number */
  793.             sprintf (portname, "%s_%d", md->portname, cntr);
  794.  
  795.             /* see if someone has already taken this name */
  796.             if (!FindPort (portname))  exist = FALSE;
  797.             cntr++;
  798.         }
  799.         /* allocate the port */
  800.         if (md->rxport = CreatePort (portname, 0L))
  801.             retval = TRUE;
  802.         Permit ();         /* permit multi-tasking again */
  803.  
  804.         if (mh = (struct MsgHandler *)
  805.             AllocMem (sizeof (struct MsgHandler), MEMF_CLEAR))
  806.         {
  807.             mh->mh_Node.ln_Name = "AREXX";
  808.             mh->mh_SigBits = (1L << md->rxport->mp_SigBit);
  809.             mh->mh_Func[MH_OPEN] = NULL;
  810.             mh->mh_Func[MH_HANDLE] = handle_arexx;
  811.             mh->mh_Func[MH_CLOSE] = NULL;
  812.             mh->mh_Func[MH_SHUTDOWN] = shutdown_arexx;
  813.             mh->mh_Data = md;
  814.  
  815.             /* open immediately? */
  816.             if (immed)
  817.             {
  818.                     if (open_arexx (ai, mh))
  819.                     return (mh);
  820.             }
  821.             else
  822.                 return (mh);
  823.  
  824.             FreeMem (mh, sizeof (struct MsgHandler));
  825.         }
  826.         else
  827.             NotifyUser (NULL, "Not enough memory");
  828.  
  829.         /* make a nice clean failure path */
  830.         DeletePort (md->rxport);
  831.         CloseLibrary ((struct Library *) RexxSysBase);
  832.         md->rxport = NULL;
  833.         RexxSysBase = NULL;
  834.     }
  835.         else
  836.         NotifyUser (NULL, "Could not open rexxsyslib.library");
  837.  
  838.     FreeMem (md, sizeof (struct data_arexx));
  839.     }
  840.     return (mh);
  841. }
  842.  
  843. BOOL open_arexx (struct AppInfo * ai, struct MsgHandler * mh)
  844. {
  845.     struct data_arexx * md = mh->mh_Data;
  846.  
  847.     md->astatus = AR_EXECUTE;
  848.     return (TRUE);
  849. }
  850.  
  851. /* ARexx message processing */
  852. BOOL handle_arexx (struct AppInfo * ai, struct MsgHandler * mh)
  853. {
  854.     struct RexxMsg *rmsg;    /* incoming ARexx messages */
  855.     struct data_arexx * md = mh->mh_Data;
  856.  
  857.     while (rmsg = (struct RexxMsg *) GetMsg (md->rxport))
  858.     {
  859.     if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
  860.     {
  861.         /* This is a reply to a previous message */
  862.         if (rmsg->rm_Result1)
  863.         {
  864.             /* returned an error message */
  865.             printf ("ARexx macro error\n");
  866.         }
  867.         /* Free up the resources used for an ARexx message */
  868.  
  869.         /* delete the argument that we originally sent */
  870.         DeleteArgstring (rmsg->rm_Args[0]);
  871.  
  872.         /* delete the extended message */
  873.         DeleteRexxMsg (rmsg);
  874.  
  875.         /* decrement the count of outstanding messages */
  876.         ai->numcmds--;
  877.     }
  878.     else
  879.     {
  880.         /* We have received a command/function message */
  881.         execute_command (rmsg, ai, mh);
  882.     }
  883.     }
  884.     return (TRUE);
  885. }
  886.  
  887. BOOL close_arexx (struct AppInfo * ai, struct MsgHandler * mh)
  888. {
  889.     struct data_arexx * md = mh->mh_Data;
  890.     md->astatus = AR_SUSPEND;
  891.     return (TRUE);
  892. }
  893.  
  894. BOOL shutdown_arexx (struct AppInfo * ai, struct MsgHandler * mh)
  895. {
  896.     struct data_arexx * md = mh->mh_Data;
  897.  
  898.     if (mh)
  899.     {
  900.     if (md->rxport)
  901.         DeletePort (md->rxport);
  902.  
  903.     Remove ((struct Node *) mh);
  904.     FreeMem (mh, sizeof (struct MsgHandler));
  905.     }
  906.  
  907.     if (RexxSysBase)
  908.     CloseLibrary ((struct Library *) RexxSysBase);
  909.  
  910.     return (TRUE);
  911. }
  912.  
  913. BOOL send_rexx_command (UBYTE * buff, struct AppInfo * ai,
  914.             struct MsgHandler * mh)
  915. {
  916.     struct MsgPort *rexxport;    /* this will be rexx's port */
  917.     struct RexxMsg *rexx_command_message;    /* this is the message */
  918.     struct data_arexx * md = mh->mh_Data;
  919.  
  920.     /* lock things temporarily */
  921.     Forbid ();
  922.  
  923.     /* if ARexx is not active, just return FALSE */
  924.     if (!(rexxport = FindPort (RXSDIR)))
  925.     {
  926.     Permit ();
  927.     return (FALSE);
  928.     }
  929.  
  930.     /* allocate a message packet for our command */
  931.     /* note that this is a very important call.  Much flexibility is */
  932.     /* available to you here by using multiple host port names, etc. */
  933.     if (!(rexx_command_message = CreateRexxMsg (md->rxport,
  934.                 md->extens,
  935.                 md->rxport->mp_Node.ln_Name)))
  936.     {
  937.     Permit ();
  938.     return (FALSE);
  939.     }
  940.  
  941.     /* create an argument string and install it in the message */
  942.     if (!(rexx_command_message->rm_Args[0] =
  943.       CreateArgstring (buff, strlen (buff))))
  944.     {
  945.     DeleteRexxMsg (rexx_command_message);
  946.     Permit ();
  947.     return (FALSE);
  948.     }
  949.  
  950.     /* indicate that message is a command */
  951.     rexx_command_message->rm_Action = RXCOMM;
  952.  
  953.     /* send the message */
  954.     PutMsg (rexxport, (struct Message *) rexx_command_message);
  955.  
  956.     /* increment the number of outstanding messages */
  957.     ai->numcmds++;
  958.  
  959.     Permit ();
  960.  
  961.     return (TRUE);
  962. }
  963.  
  964. VOID execute_command (struct RexxMsg * rmsg, struct AppInfo * ai,
  965.               struct MsgHandler * mh)
  966. {
  967.     struct data_arexx * md = mh->mh_Data;
  968.     UBYTE *cmd = ARG0 (rmsg);
  969.  
  970.     /* preset the ARexx error return values */
  971.     ai->pri_ret = 5L;
  972.     ai->sec_ret = 0L;
  973.     ai->textrtn = NULL;
  974.  
  975.     /* Don't perform function if we are suspended */
  976.     if (md->astatus == AR_EXECUTE)
  977.     PerfFunc (ai, (struct Message *) rmsg, cmd);
  978.     else
  979.     ai->pri_ret = 100L;
  980.  
  981.     /* reply to the message */
  982.     reply_rexx_command (rmsg, ai, mh);
  983. }
  984.  
  985. /* Replys to a ARexx message */
  986. VOID reply_rexx_command (struct RexxMsg * rmsg, struct AppInfo * ai,
  987.              struct MsgHandler * mh)
  988. {
  989.     /* set an error code */
  990.     if (ai->pri_ret == 0 && (rmsg->rm_Action & 1L << RXFB_RESULT))
  991.     {
  992.     ai->sec_ret = ai->textrtn ?
  993.     (LONG) CreateArgstring (ai->textrtn, strlen (ai->textrtn))
  994.     : (LONG) NULL;
  995.     }
  996.     rmsg->rm_Result1 = ai->pri_ret;
  997.     rmsg->rm_Result2 = ai->sec_ret;
  998.     ReplyMsg ((struct Message *) rmsg);
  999. }
  1000.  
  1001.  
  1002.  
  1003. /* mod_dos.c
  1004.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  1005.  * written by David N. Junod
  1006.  *
  1007.  * DOS command shell message handling routines
  1008.  */
  1009. #include "mod.h"
  1010.  
  1011. /* variables required for a DOS shell */
  1012. struct data_dos
  1013. {
  1014.     struct MsgPort *drport;    /* DOS reply port */
  1015.     UBYTE *winspec;            /* Shell window spec */
  1016.     UBYTE *closing_msg;        /* Closing message */
  1017.     BPTR acons;                /* Console file handle */
  1018.     struct StandardPacket *dmsg;/* DOS packet */
  1019.     UBYTE aprompt[25];        /* prompt */
  1020.     BOOL packet_out;            /* is a READ outstanding? */
  1021.     UBYTE buff[BUFFLEN + 1];    /* used for reading user input */
  1022.     struct Process *atask;    /* Our own process structure */
  1023.     BPTR old_CIS;            /* Orig. console input stream */
  1024.     BPTR old_COS;            /* Orig. console output stream */
  1025.     APTR old_ConsoleTask;        /* Orig. console task */
  1026.     SHORT dstatus;            /* The current status of the shell */
  1027. };
  1028.  
  1029. /* DOS message handling routines */
  1030. VOID DisplayPrompt ( struct MsgHandler *mh );
  1031. struct StandardPacket *setup_dos_message ( void );
  1032. VOID send_read_packet (struct StandardPacket *,BPTR,struct MsgPort *, UBYTE *);
  1033.  
  1034. struct MsgHandler *setup_dos (struct AppInfo * ai, UBYTE * winspec, 
  1035.                 UBYTE * prompt, UBYTE * close, BOOL immed)
  1036. {
  1037.     struct MsgHandler *mh = NULL;
  1038.     struct data_dos *md = NULL;
  1039.  
  1040.     if (md = (struct data_dos *)
  1041.     AllocMem (sizeof (struct data_dos), MEMF_CLEAR))
  1042.     {
  1043.     /* initialize data */
  1044.     md->closing_msg = close;
  1045.     md->winspec = winspec;
  1046.     strcpy (md->aprompt, prompt);
  1047.  
  1048.     /* get the current process information */
  1049.     md->atask = (struct Process *) FindTask (0);
  1050.  
  1051.     /* make backups of the default task information */
  1052.     md->old_CIS = md->atask->pr_CIS;
  1053.     md->old_COS = md->atask->pr_COS;
  1054.     md->old_ConsoleTask = md->atask->pr_ConsoleTask;
  1055.     md->packet_out = FALSE;
  1056.  
  1057.     /* Mark shell window as being closed */
  1058.     md->dstatus = AS_CLOSED;
  1059.  
  1060.     /* set up a port for DOS replys */
  1061.     if (md->drport = CreatePort (NULL, 0L))
  1062.     {
  1063.       /* set up a DOS packet for the asynchronous read from the window */
  1064.       if (md->dmsg = setup_dos_message ())
  1065.       {
  1066.         mh = (struct MsgHandler *) AllocMem (sizeof (struct MsgHandler), MEMF_CLEAR);
  1067.  
  1068.         if (mh)
  1069.         {
  1070.             mh->mh_Node.ln_Name = "DOS";
  1071.             mh->mh_SigBits = (1L << md->drport->mp_SigBit);
  1072.             mh->mh_Func[MH_OPEN] = open_dos;
  1073.             mh->mh_Func[MH_HANDLE] = handle_dos;
  1074.             mh->mh_Func[MH_CLOSE] = close_dos;
  1075.             mh->mh_Func[MH_SHUTDOWN] = shutdown_dos;
  1076.             mh->mh_Data = md;
  1077.  
  1078.             /* open immediately? */
  1079.             if (immed)
  1080.             {
  1081.                 if (open_dos (ai, mh))
  1082.                         return (mh);
  1083.             }
  1084.             else
  1085.                 return (mh);
  1086.  
  1087.             FreeMem (mh, sizeof (struct MsgHandler));
  1088.         }
  1089.         else
  1090.             NotifyUser (NULL, "Not enough memory");
  1091.  
  1092.         FreeMem (md->dmsg, sizeof (struct StandardPacket));
  1093.         md->dmsg = NULL;
  1094.       }
  1095.       DeletePort (md->drport);
  1096.       md->drport = NULL;
  1097.     }
  1098.     FreeMem (md, sizeof (struct data_dos));
  1099.     }
  1100.     return (mh);
  1101. }
  1102.  
  1103. BOOL open_dos (struct AppInfo * ai, struct MsgHandler * mh)
  1104. {
  1105.     struct data_dos *md = mh->mh_Data;
  1106.     struct FileHandle *handle;
  1107.     if (!md->acons)
  1108.     {
  1109.     if (md->acons = Open (md->winspec, MODE_NEWFILE))
  1110.     {
  1111.         /* Set the standard input/output to this console window */
  1112.         md->atask->pr_CIS = md->acons;
  1113.         md->atask->pr_COS = md->acons;
  1114.  
  1115.         /* Convert the BPTR to a C pointer */
  1116.         handle = (struct FileHandle *) (md->acons << 2);
  1117.  
  1118.         /* Set the console task in case they open a window off ours */
  1119.         md->atask->pr_ConsoleTask = (APTR) handle->fh_Type;
  1120.  
  1121.         /* Display the prompt */
  1122.         DisplayPrompt (mh);
  1123.         md->dstatus = AS_OPEN;
  1124.  
  1125.         /* send a packet out for user input */
  1126.         if (!md->packet_out)
  1127.         {
  1128.         /* send a packet to DOS asking for user keyboard input */
  1129.         send_read_packet (md->dmsg, md->acons, md->drport, md->buff);
  1130.         md->packet_out = TRUE;
  1131.         }
  1132.  
  1133.     }
  1134.     }
  1135.     return ((BOOL) ((md->acons) ? TRUE : FALSE));
  1136. }
  1137. /* handle DOS messages */
  1138. BOOL handle_dos (struct AppInfo * ai, struct MsgHandler * mh)
  1139. {
  1140.     struct data_dos *md = mh->mh_Data;
  1141.     if (GetMsg (md->drport))
  1142.     {
  1143.     /* not out any more */
  1144.     md->packet_out = FALSE;
  1145.  
  1146.     /* If the shell CLOSE gadget was hit, or ^\ */
  1147.     if (md->dmsg->sp_Pkt.dp_Res1 == 0)
  1148.     {
  1149.         md->dstatus = AS_GOING;
  1150.     }
  1151.     else
  1152.     {
  1153.         md->buff[md->dmsg->sp_Pkt.dp_Res1 - 1] = 0;
  1154.  
  1155.         if (strlen (md->buff) > 0)
  1156.         {    
  1157.             PerfFunc (ai, NULL, md->buff);        /* perform the function */
  1158.         
  1159.             DisplayPrompt (mh);                /* display the prompt */
  1160.         }
  1161.         else
  1162.             /* they entered a blank line, let's end the shell */
  1163.             md->dstatus = AS_GOING;
  1164.     }
  1165.     /* send out a packet for user input */
  1166.     if (!md->packet_out && md->dstatus >= AS_OPEN)
  1167.     {
  1168.         /* send a packet to DOS asking for user keyboard input */
  1169.         send_read_packet (md->dmsg, md->acons, md->drport, md->buff);
  1170.         md->packet_out = TRUE;
  1171.     }
  1172.     close_dos (ai, mh);
  1173.     }
  1174.     return (TRUE);
  1175. }
  1176.  
  1177. BOOL close_dos (struct AppInfo * ai, struct MsgHandler * mh)
  1178. {
  1179.     struct data_dos *md = mh->mh_Data;
  1180.  
  1181.     if (md->dstatus == AS_GOING)
  1182.     {
  1183.     /* User has indicated that he wants to close the command shell. */
  1184.     md->dstatus = AS_CLOSING;
  1185.     Write (md->acons, md->closing_msg, (LONG) strlen (md->closing_msg));
  1186.     }
  1187.  
  1188.     if (md->dstatus == AS_CLOSING && !ai->numcmds)
  1189.     {
  1190.     if (md->acons)
  1191.     {
  1192.         /* safely restore the default information */
  1193.         md->atask->pr_CIS = md->old_CIS;
  1194.         md->atask->pr_COS = md->old_COS;
  1195.         md->atask->pr_ConsoleTask = md->old_ConsoleTask;
  1196.  
  1197.         /* close the console window */
  1198.         Close (md->acons);
  1199.     }
  1200.  
  1201.     md->dstatus = AS_CLOSED;
  1202.       md->acons = NULL;
  1203.     }
  1204.     return ((BOOL) ((md->acons) ? TRUE : FALSE));
  1205. }
  1206.  
  1207. BOOL shutdown_dos (struct AppInfo * ai, struct MsgHandler * mh)
  1208. {
  1209.     struct data_dos *md = mh->mh_Data;
  1210.     if (mh)
  1211.     {
  1212.     if (md)
  1213.     {
  1214.         if (md->acons)
  1215.             md->dstatus = AS_GOING;
  1216.         close_dos (ai, mh);
  1217.  
  1218.         if (md->drport)
  1219.             DeletePort (md->drport);
  1220.  
  1221.         if (md->dmsg)
  1222.             FreeMem (md->dmsg, sizeof (struct StandardPacket));
  1223.     }
  1224.  
  1225.     Remove ((struct Node *) mh);
  1226.     FreeMem (mh, sizeof (struct MsgHandler));
  1227.     }
  1228.  
  1229.     return (TRUE);
  1230. }
  1231.  
  1232. VOID DisplayPrompt (struct MsgHandler * mh)
  1233. {
  1234.     struct data_dos *md = mh->mh_Data;
  1235.  
  1236.     Write (md->acons, md->aprompt, (LONG) strlen (md->aprompt));
  1237. }
  1238.  
  1239. struct StandardPacket *setup_dos_message ()
  1240. {
  1241.     struct StandardPacket *new_packet;
  1242.  
  1243.     /* get a packet */
  1244.     if (new_packet = (struct StandardPacket *)
  1245.         AllocMem (sizeof (struct StandardPacket), MEMF_CLEAR))
  1246.     {
  1247.     new_packet->sp_Msg.mn_Node.ln_Name =
  1248.       (UBYTE *) & (new_packet->sp_Pkt);
  1249.     new_packet->sp_Pkt.dp_Link = &(new_packet->sp_Msg);
  1250.     }
  1251.     return (new_packet);
  1252. }
  1253.  
  1254. VOID send_read_packet (struct StandardPacket * dos_message,
  1255.                 BPTR console_fh,
  1256.                 struct MsgPort * dos_reply_port,
  1257.                 UBYTE * buff)
  1258. {
  1259.     struct FileHandle *file_handle;
  1260.  
  1261.     /* change a BPTR to a REAL pointer */
  1262.     file_handle = (struct FileHandle *) (console_fh << 2);
  1263.     /* setup the packet for reading */
  1264.     dos_message->sp_Pkt.dp_Arg1 = file_handle->fh_Arg1;
  1265.     dos_message->sp_Pkt.dp_Arg2 = (LONG) buff;
  1266.     dos_message->sp_Pkt.dp_Arg3 = BUFFLEN;
  1267.     dos_message->sp_Pkt.dp_Type = ACTION_READ;
  1268.     dos_message->sp_Pkt.dp_Port = dos_reply_port;
  1269.     dos_message->sp_Msg.mn_ReplyPort = dos_reply_port;
  1270.  
  1271.     /* now send it */
  1272.     PutMsg (file_handle->fh_Type, (struct Message *) dos_message);
  1273. }
  1274.  
  1275.  
  1276. /* mod_idcmp.c
  1277.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  1278.  * written by David N. Junod
  1279.  *
  1280.  * IDCMP gadget/menu/keyboard message handling routines
  1281.  */
  1282.  
  1283. #include "mod.h"
  1284.  
  1285. #define    idcmp_flags (CLOSEWINDOW | RAWKEY | MOUSEMOVE | MOUSEBUTTONS \
  1286.              | INTUITICKS | GADGETDOWN | GADGETUP | MENUPICK)
  1287.  
  1288. #define SHIFTED (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)
  1289. #define ALTED (IEQUALIFIER_LALT | IEQUALIFIER_RALT)
  1290.  
  1291. /* variables required for IDCMP message handling */
  1292. struct data_idcmp
  1293. {
  1294.     struct MsgPort *msgport;    /* Message port */
  1295.     struct NewWindow *nw;    /* NewWindow pointer */
  1296.     struct Menu *menu;        /* Menu strip pointer */
  1297.     WORD *KeyFunctions;        /* Keyboard function map */
  1298.     struct Window *win;        /* Window */
  1299.     struct EGadget *ActiveGad;    /* Currrently active gadget */
  1300.     struct IOStdReq ioreq;    /* Rawkey conversion IO request */
  1301. };
  1302.  
  1303. BOOL setup_key_array (struct data_idcmp * mh, struct KeyboardCMD * KeyArray);
  1304. VOID shutdown_key_array (struct data_idcmp *);
  1305. LONG DeadKeyConvert(struct IntuiMessage * msg, UBYTE * kbuffer, LONG kbsize, struct KeyMap * kmap);
  1306. VOID CloseWindowSafely (struct Window * win);
  1307. VOID HandleKeyEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  1308. VOID HandleGadgEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  1309. VOID HandleMenuEvent(struct AppInfo *,struct MsgHandler *,struct IntuiMessage * msg);
  1310.  
  1311. /* Required for DeadKeyConvert processing */
  1312. struct ConsoleDevice *ConsoleDevice = NULL;
  1313.  
  1314. /* setup the resources required for IDCMP processing */
  1315. struct MsgHandler *setup_idcmp (struct AppInfo * ai,
  1316.                 struct NewWindow * nw,
  1317.                 struct KeyboardCMD * kba,
  1318.                 struct Menu * menu, BOOL immed)
  1319. {
  1320.     struct MsgHandler *mh = NULL;
  1321.     struct data_idcmp *md = NULL;
  1322.  
  1323.     if (md = (struct data_idcmp *)
  1324.     AllocMem (sizeof (struct data_idcmp), MEMF_CLEAR))
  1325.     {
  1326.     md->nw = nw;
  1327.     md->menu = menu;
  1328.     if (setup_key_array (md, kba))
  1329.     {
  1330.         if (md->msgport = CreatePort (NULL, 0))
  1331.         {
  1332.         if (mh = (struct MsgHandler *)
  1333.             AllocMem (sizeof (struct MsgHandler), MEMF_CLEAR))
  1334.         {            
  1335.             mh->mh_SigBits = (1L << md->msgport->mp_SigBit);
  1336.             mh->mh_Func[MH_OPEN]     = open_idcmp;
  1337.             mh->mh_Func[MH_HANDLE]   = handle_idcmp;
  1338.             mh->mh_Func[MH_CLOSE]    = close_idcmp;
  1339.             mh->mh_Func[MH_SHUTDOWN] = shutdown_idcmp;
  1340.             mh->mh_Data = md;
  1341.  
  1342.                   if (immed)
  1343.             {
  1344.                 if (open_idcmp (ai, mh))
  1345.                     return (mh);
  1346.             }
  1347.             else
  1348.                 return (mh);
  1349.  
  1350.             FreeMem (mh, sizeof (struct MsgHandler));
  1351.         }
  1352.         else
  1353.             NotifyUser (NULL, "Not enough memory");
  1354.         }
  1355.         else
  1356.             NotifyUser (NULL, "Could not create IDCMP port");
  1357.     }
  1358.     FreeMem (md, sizeof (struct data_idcmp));
  1359.     }
  1360.     return (mh);
  1361. }
  1362.  
  1363. /* activate IDCMP handler */
  1364. BOOL open_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  1365. {
  1366.     struct data_idcmp *md = mh->mh_Data;
  1367.  
  1368.     if (!(md->win))
  1369.     {
  1370.     /* Open an Intuition window */
  1371.     md->nw->IDCMPFlags = NULL;
  1372.     if (md->win = OpenWindow (md->nw))
  1373.     {
  1374.         /* Attach the menu strip. You should pass it thru the AdjustMenu
  1375.          * function that is shown in the 1.3 RKM Libraries & Devices menu
  1376.          * example. */
  1377.         SetMenuStrip (md->win, md->menu);
  1378.  
  1379.         /* set up the message port information */
  1380.         md->win->UserPort = md->msgport;
  1381.         ModifyIDCMP (md->win, idcmp_flags);
  1382.  
  1383.         return (TRUE);
  1384.     }
  1385.     else
  1386.         NotifyUser (NULL, "Could not open window");
  1387.     }
  1388.     return (FALSE);
  1389. }
  1390.  
  1391. /* Intuition message processing */
  1392. BOOL handle_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  1393. {
  1394.     struct data_idcmp *md = mh->mh_Data;
  1395.     struct IntuiMessage *imsg;    /* incoming Intuition messages */
  1396.     struct IntuiMessage *fmsg, *tmsg; /* for filtering messages */
  1397.     struct Window * win; /* only used for filtering messages */
  1398.     struct IntuiMessage nmsg;    /* copy of the message */
  1399.  
  1400.     while (imsg = (struct IntuiMessage *) GetMsg (md->msgport))
  1401.     {
  1402.     /* Filter out excessive mouse-moves (oldest first) */
  1403.     if (imsg->Class == MOUSEMOVE)
  1404.     {
  1405.         win = imsg->IDCMPWindow;
  1406.         Forbid ();
  1407.         fmsg = (struct IntuiMessage *)
  1408.                 (md->msgport->mp_MsgList.lh_Head);
  1409.         while (tmsg = (struct IntuiMessage *)
  1410.            (fmsg->ExecMessage.mn_Node.ln_Succ))
  1411.         {
  1412.             if (fmsg->IDCMPWindow == win &&
  1413.                 fmsg->Class == MOUSEMOVE)
  1414.             {
  1415.                     Remove ((struct Node *) fmsg);
  1416.                     ReplyMsg ((struct Message *) imsg);
  1417.                     imsg = fmsg;
  1418.             }
  1419.             fmsg = tmsg;
  1420.         }
  1421.         Permit ();
  1422.     }
  1423.     /* Filter out excessive key repeats here. Amiga Mail article by
  1424.      * Michael Sinz IV-37 Paced Repeat Key */
  1425.  
  1426.     /* copy the message so that we can reply to it */
  1427.     CopyMem ( (APTR)imsg, (APTR)&nmsg, sizeof (struct IntuiMessage) );
  1428.  
  1429.     /* Reply to the message now that we're done with it */
  1430.     ReplyMsg ((struct Message *) imsg);
  1431.  
  1432.     /* Process Intuition events */
  1433.     switch (nmsg.Class)
  1434.     {
  1435.         /* Handle the close window gadget */
  1436.         case CLOSEWINDOW:
  1437.                 QuitFunc (ai, (struct Message *) &nmsg, NULL);
  1438.             break;
  1439.  
  1440.         /* Handle keyboard events */
  1441.         case RAWKEY:
  1442.             HandleKeyEvent (ai, mh, &nmsg);
  1443.             break;
  1444.  
  1445.         /* Handle events that pertain to gadgets */
  1446.         case INTUITICKS:
  1447.         case MOUSEMOVE:
  1448.         case MOUSEBUTTONS:
  1449.         case GADGETDOWN:
  1450.         case GADGETUP:
  1451.             HandleGadgEvent (ai, mh, &nmsg);
  1452.             break;
  1453.  
  1454.         /* Handle menu events */
  1455.         case MENUPICK:
  1456.             HandleMenuEvent (ai, mh, &nmsg);
  1457.             break;
  1458.     }
  1459.     }
  1460.     return (TRUE);
  1461. }
  1462.  
  1463.  
  1464.  
  1465.  
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471.  
  1472.  
  1473.  
  1474.  
  1475.  
  1476.  
  1477. /* hide IDCMP message handler */
  1478. BOOL close_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  1479. {
  1480.     struct data_idcmp *md = mh->mh_Data;
  1481.  
  1482.     if (mh)
  1483.     {
  1484.     if (md->win)
  1485.     {
  1486.         /* save current settings */
  1487.         md->nw->Width = md->win->Width;
  1488.         md->nw->Height = md->win->Height;
  1489.         md->nw->LeftEdge = md->win->LeftEdge;
  1490.         md->nw->TopEdge = md->win->TopEdge;
  1491.  
  1492.         /* clear the menu strip if there is one */
  1493.         if (md->win->MenuStrip)
  1494.             ClearMenuStrip (md->win);
  1495.  
  1496.         /* close the window */
  1497.         CloseWindowSafely (md->win);
  1498.         md->win = NULL;
  1499.     }
  1500.     }
  1501.     return (TRUE);
  1502. }
  1503.  
  1504. /* free resources for IDCMP message handler */
  1505. BOOL shutdown_idcmp (struct AppInfo * ai, struct MsgHandler * mh)
  1506. {
  1507.     struct data_idcmp *md = mh->mh_Data;
  1508.  
  1509.     if (mh)
  1510.     {
  1511.     close_idcmp (ai, mh);        /* close window */
  1512.     shutdown_key_array (md);    /* free keyboard array */
  1513.  
  1514.     DeletePort (md->msgport);    /* delete IDCMP port */
  1515.     md->msgport = NULL;
  1516.     }
  1517.     return (TRUE);
  1518. }
  1519.  
  1520. /* safely close a window that shares a message port with another window */
  1521. VOID CloseWindowSafely (struct Window * win)
  1522. {
  1523.     struct IntuiMessage * msg, * succ;
  1524.  
  1525.     Forbid ();
  1526.  
  1527.     msg = (struct IntuiMessage *)win->UserPort->mp_MsgList.lh_Head;
  1528.     while (succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ)
  1529.     {
  1530.     if (msg->IDCMPWindow == win)
  1531.     {
  1532.         Remove ((struct Node *)msg);
  1533.         ReplyMsg ((struct Message *)msg);
  1534.     }
  1535.     msg = succ;
  1536.     }
  1537.     win->UserPort = NULL;
  1538.     ModifyIDCMP (win, NULL);
  1539.  
  1540.     Permit ();
  1541.     CloseWindow (win);
  1542. }
  1543.  
  1544. /* Allocate resources for handling keyboard input */
  1545. BOOL setup_key_array (struct data_idcmp * md, struct KeyboardCMD * KeyArray)
  1546. {
  1547.     register WORD cntr;
  1548.  
  1549.     /* Allow for NULL specification of a keyboard command array */
  1550.     if (!KeyArray)
  1551.     return (TRUE);
  1552.  
  1553.     /* Prepare for DeadKeyConvert */
  1554.     if (!(OpenDevice ("console.device", -1L,
  1555.               (struct IORequest *) & (md->ioreq), 0L)))
  1556.     {
  1557.     ConsoleDevice = (struct ConsoleDevice *) md->ioreq.io_Device;
  1558.  
  1559.     /* Allocate memory for the keyboard function map */
  1560.     if (md->KeyFunctions = AllocMem ((sizeof (WORD) * MAXKEYS), MEMF_CLEAR))
  1561.     {
  1562.         /* read in the key assignments */
  1563.         for (cntr = 0; KeyArray[cntr].key != NULL; cntr++)
  1564.         md->KeyFunctions[KeyArray[cntr].key] = KeyArray[cntr].funcID;
  1565.         return (TRUE);
  1566.     }
  1567.     else
  1568.         NotifyUser (NULL, "Not enough memory");
  1569.  
  1570.     CloseDevice ((struct IORequest *) & (md->ioreq));
  1571.     }
  1572.     else
  1573.     NotifyUser (NULL, "Could not open console.device");
  1574.  
  1575.     return (FALSE);
  1576. }
  1577.  
  1578. /* Release resources for handling keyboard input */
  1579. VOID shutdown_key_array (struct data_idcmp * md)
  1580. {
  1581.     if (md)
  1582.     {
  1583.     if (md->KeyFunctions)
  1584.         FreeMem (md->KeyFunctions, (sizeof (WORD) * MAXKEYS));
  1585.     md->KeyFunctions = NULL;
  1586.  
  1587.     if (ConsoleDevice)
  1588.         CloseDevice ((struct IORequest *) & (md->ioreq));
  1589.     }
  1590. }
  1591.  
  1592. /* Keyboard handling routines */
  1593. VOID HandleKeyEvent (struct AppInfo * ai, struct MsgHandler * mh,
  1594.              struct IntuiMessage * msg)
  1595. {
  1596.     struct data_idcmp *md = mh->mh_Data;
  1597.     WORD FuncID = NO_FUNCTION;
  1598.     WORD key, cur;
  1599.     UBYTE buffer[17];
  1600.  
  1601.     strcpy (buffer, "               ");
  1602.     key = (WORD) DeadKeyConvert (msg, buffer, 15L, 0L);
  1603.     if (key > 0)
  1604.     {
  1605.     /* Get the ASCII value of the key that was pressed */
  1606.     cur = buffer[0];
  1607.  
  1608.     /* Check to see if it was a special key; like a Function key, Help, or
  1609.      * the Arrow keys.  Could also do additional checking for ALT, AMIGA
  1610.      * and CTRL qualifiers by adding in a weight for each one. */
  1611.     if (key > 1 && cur == 155)
  1612.         cur = SPECIAL + buffer[1];
  1613.  
  1614.     /* Get the function number assigned to this key */
  1615.     FuncID = md->KeyFunctions[cur];
  1616.  
  1617.     if (FuncID != NO_FUNCTION)
  1618.         /* Perform the function assigned to this key. */
  1619.         PerfFunc (ai, NULL, ai->FuncTable[FuncID].name);
  1620.     else
  1621.     {
  1622.         /* No function has been defined for this key, so you could
  1623.          * do other processing to it. */
  1624.     }
  1625.     }
  1626. }
  1627.  
  1628. /* Convert Raw keys to Vanilla keys */
  1629. LONG DeadKeyConvert (msg, kbuffer, kbsize, kmap)
  1630.     struct IntuiMessage *msg;
  1631.     UBYTE *kbuffer;
  1632.     LONG kbsize;
  1633.     struct KeyMap *kmap;
  1634. {
  1635.     static struct InputEvent ievent =
  1636.     {NULL, IECLASS_RAWKEY, 0, 0, 0};
  1637.  
  1638.     if (msg->Class != RAWKEY)
  1639.     return (-2);
  1640.     ievent.ie_Code = msg->Code;
  1641.     ievent.ie_Qualifier = msg->Qualifier;
  1642.     ievent.ie_position.ie_addr = *((APTR *) msg->IAddress);
  1643.  
  1644.     return (RawKeyConvert (&ievent, kbuffer, kbsize, kmap));
  1645. }
  1646.  
  1647. /* Gadget handling routine */
  1648. VOID HandleGadgEvent (struct AppInfo * ai, struct MsgHandler * mh,
  1649.               struct IntuiMessage * msg)
  1650. {
  1651.     struct data_idcmp *md = mh->mh_Data;
  1652.     struct EGadget *egad = (struct EGadget *) msg->IAddress;
  1653.     WORD FuncID = NO_FUNCTION;
  1654.     static ULONG glsecs = 0L, glmics = 0L;    /* For Gadget DoubleClick */
  1655.  
  1656.     switch (msg->Class)
  1657.     {
  1658.     /* Check to see if gadget is being held down and if there is a
  1659.      * function to perform while it is being held. */
  1660.     case MOUSEMOVE:
  1661.     case INTUITICKS:
  1662.         if (md->ActiveGad &&
  1663.             md->ActiveGad->eg_Gadget.Flags & SELECTED)
  1664.         {
  1665.           FuncID = md->ActiveGad->eg_Funcs[EG_HOLD];
  1666.         }
  1667.         break;
  1668.  
  1669.     /* Indicate that there is no active gadget now. */
  1670.     case MOUSEBUTTONS:
  1671.         if (msg->Code == SELECTUP)
  1672.             md->ActiveGad = NULL;
  1673.         break;
  1674.  
  1675.     /* Check to see if there is a function to perform on downpress or
  1676.      * double-click of the gadget. */
  1677.     case GADGETDOWN:
  1678.  
  1679.         /* Set the active gadget.  Only one gadget can EVER be active
  1680.          * at a time (Intuition rule). */
  1681.         md->ActiveGad = egad;
  1682.  
  1683.         FuncID = egad->eg_Funcs[EG_DOWNPRESS];
  1684.         if (egad->eg_Funcs[EG_DBLCLICK] != NO_FUNCTION)
  1685.         {
  1686.  
  1687.             /* If the gadget has a double-click function, then check to
  1688.              * see if it has been double-clicked.  Notice that if there
  1689.              * is a double-click function, then it over-rules the
  1690.              *downpress function. */
  1691.             if (DoubleClick (glsecs, glmics, msg->Seconds, msg->Micros))
  1692.                     FuncID = egad->eg_Funcs[EG_DBLCLICK];
  1693.             else
  1694.             {
  1695.                 glsecs = msg->Seconds;
  1696.                 glmics = msg->Micros;
  1697.             }
  1698.         }
  1699.         break;
  1700.  
  1701.     /* Check to see if there is a function to perform on release of the
  1702.      * gadget. */
  1703.     case GADGETUP:
  1704.         /* Clear the active gadget variable */
  1705.         md->ActiveGad = NULL;
  1706.  
  1707.         FuncID = egad->eg_Funcs[EG_RELEASE];
  1708.         break;
  1709.     }
  1710.  
  1711.     /* Perform the function if there is one. */
  1712.     if (FuncID != NO_FUNCTION)
  1713.     PerfFunc (ai, NULL, ai->FuncTable[FuncID].name);
  1714. }
  1715.  
  1716. /* Menu handling routine */
  1717. VOID HandleMenuEvent (struct AppInfo * ai, struct MsgHandler * mh,
  1718.               struct IntuiMessage * msg)
  1719. {
  1720.     struct EMenuItem *item;
  1721.     UWORD selection = msg->Code;
  1722.  
  1723.     /* Shut down menu events while we're processing these. Any function that
  1724.      * opens its own window and ignores events from the main window, should
  1725.      * also set a busy pointer in the main window. */
  1726.     msg->IDCMPWindow->Flags |= RMBTRAP;
  1727.  
  1728.     /* Process all menu events */
  1729.     while ((selection != MENUNULL) && (!ai->Done))
  1730.     {
  1731.     /* Get the Extended MenuItem structure address */
  1732.     item = (struct EMenuItem *)
  1733.       ItemAddress (msg->IDCMPWindow->MenuStrip, (LONG) selection);
  1734.  
  1735.     /* Mutual Excluded items should all call the same function.  And that
  1736.      * function should do any processing based on the currently selected
  1737.      * item. */
  1738.     PerfFunc (ai, NULL, ai->FuncTable[item->emi_MenuID].name);
  1739.  
  1740.     /* Get the next selection */
  1741.     selection = item->emi_Item.NextSelect;
  1742.     }
  1743.  
  1744.     /* Turn menu events back on. */
  1745.     msg->IDCMPWindow->Flags &= ~RMBTRAP;
  1746. }
  1747.  
  1748.  
  1749.  
  1750.  
  1751.  
  1752. /* mod_funcs.c
  1753.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  1754.  * written by David N. Junod
  1755.  *
  1756.  * application specific functions
  1757.  *
  1758.  */
  1759.  
  1760. #include "mod.h"
  1761.  
  1762. /*--- check to see if the project has been changed ---*/
  1763. BOOL CheckForChanges (struct AppInfo * ai)
  1764. {
  1765.     BOOL cancel = FALSE;
  1766.     UBYTE pname[255];
  1767.  
  1768.     /* See if there is a name for our project */
  1769.     strcpy (pname, ai->ProjName);
  1770.     if (strlen (pname) < 1)
  1771.     strcpy (pname, "<untitled>");
  1772.  
  1773.     /* Check to see if any changes have been made to our project */
  1774.     if (ai->Changed)
  1775.     {
  1776.  
  1777.     /* Bring up a requester stating:
  1778.      * project (pname) has been changed, do you want to save first?
  1779.      * prompt for Yes | No | Cancel
  1780.      * 
  1781.      * Yes:        call the SaveFunc(NULL, win, NULL) function.
  1782.      * No:        fall through.
  1783.      * Cancel:    set cancel=TRUE.
  1784.      */
  1785.  
  1786.     /*
  1787.      * also set ai->pri_ret so that scripts can act accordingly
  1788.      * 
  1789.      * Yes:        0
  1790.      * No:        0
  1791.      * Cancel:    5
  1792.      */
  1793.     }
  1794.     return (cancel);
  1795. }
  1796.  
  1797. VOID NewFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1798. {
  1799.     BOOL cancel;
  1800.  
  1801.     printf ("`New' function\n");
  1802.  
  1803.     cancel = CheckForChanges (ai);
  1804.     if (!cancel)
  1805.     {
  1806.     /* Free up the previous project here... */
  1807.  
  1808.     /* Prepare for a New project here... */
  1809.     strcpy (ai->ProjName, "");
  1810.     ai->Changed = FALSE;
  1811.     }
  1812. }
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820. VOID OpenFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1821. {
  1822.     BOOL cancel;
  1823.  
  1824.     printf ("`Open' function\n");
  1825.  
  1826.     cancel = CheckForChanges (ai);
  1827.     if (!cancel)
  1828.     {
  1829.     /* see if an argument was passed */
  1830.     if (strlen (args) > 0)
  1831.     {
  1832.         printf ("%s was passed\n", args);
  1833.         strcpy (ai->ProjName, args);
  1834.     }
  1835.     else
  1836.     {
  1837.         /*
  1838.          * Bring up your file requester here. Remember to check for cancel
  1839.          * being pressed...
  1840.          */
  1841.         strcpy (ai->ProjName, "Named");
  1842.     }
  1843.  
  1844.     /* Open a new project here... */
  1845.     ai->Changed = FALSE;
  1846.     }
  1847. }
  1848.  
  1849. VOID SaveFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1850. {
  1851.     printf ("`Save' function\n");
  1852.  
  1853.     if (strlen (ai->ProjName) == 0)
  1854.     {
  1855.     /* Not named yet, so let's get a name */
  1856.     SaveAsFunc (ai, msg, args);
  1857.     }
  1858.     else if (ai->Changed)
  1859.     {
  1860.     /* Save your project here ... */
  1861.     ai->Changed = FALSE;
  1862.     }
  1863. }
  1864.  
  1865. VOID SaveAsFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1866. {
  1867.     printf ("`Save As' function\n");
  1868.  
  1869.     /* see if an argument was passed */
  1870.     if (strlen (args) > 0)
  1871.     {
  1872.     /* they passed a file name to save as */
  1873.     printf ("%s was passed\n", args);
  1874.     strcpy (ai->ProjName, args);
  1875.     }
  1876.     else
  1877.     {
  1878.     /*
  1879.      * Bring up your file requester here so that user can name the project.
  1880.      * Only set the Changed flag to FALSE if the user successfully returns
  1881.      * a file name (doesn't hit CANCEL).
  1882.      */
  1883.     strcpy (ai->ProjName, "Named");
  1884.     }
  1885.  
  1886.     /* Save your project here ... */
  1887.     ai->Changed = FALSE;
  1888. }
  1889.  
  1890.  
  1891. VOID AboutFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1892. {
  1893.     printf ("`About' function\n");
  1894.  
  1895.     /* return a text value */
  1896.     ai->textrtn = "ModEngine 1.00 23-Feb-90";
  1897. }
  1898.  
  1899.  
  1900. VOID QuitFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1901. {
  1902.     printf ("`Quit' function\n");
  1903.  
  1904.     /* Inform the main loop that we are done */
  1905.     ai->Done = TRUE;
  1906. }
  1907.  
  1908.  
  1909. VOID ChooseFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1910. {
  1911.     printf ("`Choose a Tool' function\n");
  1912. }
  1913.  
  1914.  
  1915. VOID DefineFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1916. {
  1917.     printf ("`Change Tool Settings' function\n");
  1918. }
  1919.  
  1920. VOID UndoFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1921. {
  1922.     printf ("`Undo' function\n");
  1923. }
  1924.  
  1925.  
  1926. VOID HelpFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1927. {
  1928.     printf ("`Help' function\n");
  1929. }
  1930.  
  1931.  
  1932. VOID ArrowFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1933. {
  1934.     printf ("`Arrow' function\n");
  1935. }
  1936.  
  1937.  
  1938. VOID ShellFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1939. {
  1940.     printf ("`Shell' function\n");
  1941.     HandlerFunc (ai, "DOS", MH_OPEN);
  1942. }
  1943.  
  1944.  
  1945. VOID WindowFunc (struct AppInfo *ai, struct Message *msg, UBYTE * args)
  1946. {
  1947.     printf ("`Window' function\n");
  1948.     if (strcmpi (args, "CLOSE") == 0)
  1949.     HandlerFunc (ai, "IDCMP", MH_CLOSE);
  1950.     else
  1951.     HandlerFunc (ai, "IDCMP", MH_OPEN);
  1952. }
  1953.  
  1954.  
  1955.  
  1956. /* mod_misc.c
  1957.  * Copyright (C) 1990 Commodore-Amiga, Inc.
  1958.  * written by David N. Junod
  1959.  */
  1960. #include "mod.h"
  1961.  
  1962. /*--- AutoRequest support variables ---*/
  1963. extern struct TextAttr Topaz80;
  1964.  
  1965. UBYTE ErrorBuffer[255] = "\\000";
  1966.     struct IntuiText ErrorText =
  1967.     {2, 1, JAM1, 20, 15, &Topaz80, &ErrorBuffer[0], NULL};
  1968.  
  1969. struct IntuiText ctext =
  1970.     {AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, AUTOLEFTEDGE,
  1971.      AUTOTOPEDGE, &Topaz80, " CONTINUE ", NULL
  1972.     };
  1973.  
  1974. BOOL NotifyUser (struct Window * win, UBYTE * msg)
  1975. {
  1976.     struct IntuiText *errortext;
  1977.     SHORT arwidth, arheight = 60, arwadj = 60;
  1978.  
  1979.     sprintf (ErrorBuffer, "%s\\000", msg);
  1980.     errortext = &ErrorText;
  1981.     arwidth = IntuiTextLength (errortext) + arwadj;
  1982.     return ((BOOL) AutoRequest (win, errortext, NULL, &ctext,
  1983.                 0, 0, arwidth, arheight));
  1984. }
  1985.  
  1986. /* macro1.mod                        */
  1987. /* modengine1 test rexx script #1    */
  1988. /* run from ModEngine shell: macro1  */
  1989.  
  1990. options results    /* request string to be returned */
  1991. WINDOW CLOSE
  1992. NEW
  1993. say 'rc=' rc 'result=' result
  1994. OPEN my titled
  1995. say 'rc=' rc 'result=' result
  1996. OPEN
  1997. say 'rc=' rc 'result=' result
  1998. ABOUT
  1999. say 'rc=' rc 'result=' resul
  2000. SAVEAS my titled
  2001. say 'rc=' rc 'result=' result
  2002. WINDOW OPEN
  2003. say 'rc=' rc 'result=' result
  2004.  
  2005. /* rxtest.rexx                    */
  2006. /* modengine1 test rexx script #2 */
  2007. /* run from CLI: rx rxtest        */
  2008.  
  2009. options results        /* turn on string results */
  2010. address 'OURAPP_1'
  2011. NEW
  2012. ABOUT
  2013. say 'rc=' rc 'result=' result
  2014. SAVEAS my titled
  2015. OPEN my titled
  2016. SAVE
  2017. MACRO2
  2018. address
  2019.  
  2020.  
  2021.